/**
 * Copyright 2014-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.webank.fiscobcoscanal2.manager;

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.fisco.bcos.web3j.protocol.core.methods.response.SendTransaction;
import org.fisco.bcos.web3j.tx.ExtendedRawTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.webank.fiscobcoscanal2.constant.GasConstants;
import com.webank.fiscobcoscanal2.db.entity.TransactionInfo;
import com.webank.fiscobcoscanal2.db.repository.TransactionInfoRepository;

import lombok.extern.slf4j.Slf4j;

/**
 * TransactionPrepareManager
 *
 * @Description: TransactionPrepareManager
 * @author maojiayu
 * @data Oct 30, 2019 5:21:39 PM
 *
 */
@Service
@Slf4j
public class TransactionPrepareManager {

    @Autowired
    private TransactionInfoRepository transactionInfoRepostory;
    @Autowired
    private ExtendedRawTransactionManager extendedRawTransactionManager;

    public void prepare() throws InterruptedException {
        BigInteger i = BigInteger.ONE;
        while (true) {
            Optional<List<TransactionInfo>> o = transactionInfoRepostory.findByBlockHeight(i);
            if (o.isPresent()) {
                List<TransactionInfo> list = o.get();
                if (list.size() > 0) {
                    log.info("Begin to replay, block {}, size {}", i, list.size());
                    list = list.stream().filter(e -> e.getStatus() == 0).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(list)) {
                        list.stream().forEach(t -> {
                            try {
                                send(t);
                            } catch (IOException e1) {
                                log.error("{}", e1);
                            }
                        });
                    }
                }
                Thread.sleep(900L);
            }

            i = i.add(BigInteger.ONE);
        }
    }

    @Async("taskExecutor")
    public void send(TransactionInfo txInfo) throws IOException {
        log.info("begin to send block {}, index {}", txInfo.getBlockHeight(), txInfo.getIndexNumber());
        log.info("to: {} , data: {} ", txInfo.getTo(), txInfo.getData());
        SendTransaction sendTx = extendedRawTransactionManager.sendTransaction(GasConstants.GAS_PRICE,
                GasConstants.GAS_LIMIT, txInfo.getTo(), txInfo.getData(), BigInteger.ZERO, "");
        log.info("{}", sendTx.getResult());
        transactionInfoRepostory.updateStatusByPkId(txInfo.getPkId(), 1);
    }

}
